/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_SCENENODE_H
#define M_SCENENODE_H

#include "common.h"
#include "matrix4.h"
#include "refptr.h"
#include "aabb.h"
#include "renderqueue.h"
#include "signal.h"

#include <map>
#include <string>
#include <vector>

namespace Engine
{
	class Camera;
	class MovableObject;
	/**
	*   Entity of scene graph, holds transformations, childs and parent nodes.
	*   Transformation of node is relative to parents transformation.
	*/
	class SceneNode
	{
	public:
		typedef std::map<std::string, RefPtr<SceneNode, WeakPtrExtension> > ChildsMap;
		typedef std::vector<MovableObjectPtr> MovableObjectVector;

		/**
		*   Constructor.
		*/
		SceneNode(const std::string& name);

		/**
		*   Destructor.
		*/
		virtual ~SceneNode();

		/**
		*   Get node name.
		*/
		const std::string& GetName()const;

		/**
		*   Create new child node.
		*/
		virtual SceneNodePtr CreateChild(const std::string& name);

		/**
		*   Delete child node.
		*/
		virtual void DeleteChild(const std::string& name);

		/**
		*   Delete all child nodes.
		*/
		virtual void DeleteAllChilds();


		/**
		*   Move node.
		*/
		void Move(const Vector3<REAL>& pos);

		/**
		*   Move node.
		*/
		void Move(REAL x, REAL y,REAL z){Move(Vector3<REAL>(x,y,z));}

		/**
		*   Rotate node.
		*/
		void Rotate(const Vector3<REAL>& pos, REAL angle);

		/**
		*   Rotate node.
		*/
		void Rotate(REAL x, REAL y, REAL z, REAL angle){Rotate(Vector3<REAL>(x,y,z),angle);}

		/**
		*   Scale node.
		*/
		void Scale(const Vector3<REAL>& scale);

		/**
		*   Scale node.
		*/
		void Scale(REAL x, REAL y,REAL z){Scale(Vector3<REAL>(x,y,z));}

		/**
		*   Setup transformation matrix.
		*/
		void SetTransform(const Matrix4<REAL>& trans);

		/**
		*   Returns current transformation matrix.
		*/
		const Matrix4<REAL>& GetTransform() const;

		/**
		*   Returns transformation matrix including parents transformation.
		*/
		const Matrix4<REAL>& GetDerivedTransform()const;

		/**
		*   Calculate world transformation (include parents).
		*/
		void Update();

		/**
		*   Called when scene node is updating.
		*/
		Signal<> UpdateSignal;

		/**
		*   Recalculate bounding box, including child nodes and attached objects.
		*/
		virtual void UpdateBounds();

		/**
		*   Return bounding box.
		*/
		const AABB& GetBoundingBox()const;

		/**
		*   Searches for visible objects and populate render queue.
		*/
		void FindVisibleObjects(const Camera* camera, RenderQueue* renderqueue, RenderQueue* shadowsQueue, const std::vector<LightPtr>& lightList);

		/**
		*   Attach object to node.
		*/
		void AttachObject(MovableObjectPtr obj);

		/**
		*   Detach object from node.
		*/
		void DetachObject(MovableObjectPtr obj);

		/**
		*   Detach object from node.
		*/
		void DetachObject(const std::string& name);

		/**
		*   Detach all objects from node.
		*/
		void DetachAllObjects();

	protected:

		/**
		*   Return true if there are no child with given name.
		*/
		bool CheckChildName(const std::string& name);

		/**
		*   Add child node.
		*/
		SceneNodePtr AddChildNode(SceneNode* node);

		/**
		*   Searches only for  visible child movable objects and populate render queue.
		*/
		void FindVisibleMovableObjects(const Camera* camera, RenderQueue* renderqueue, RenderQueue* shadowsQueue, const std::vector<LightPtr>& lightList, Visibility vis);

	private:
		std::string       m_name;
		SceneNode*        m_parent;
		ChildsMap         m_childs;
		Matrix4<REAL>     m_transform;
		Matrix4<REAL>     m_derivedTransform;
		AABB              m_boundingBox;
		MovableObjectVector  m_movableObjects;
	};
}

#endif
